/*
 * Gameloop.cpp
 *
 *  Created on: 2-dec.-2013
 *      Author: Axel
 */

#include <Gameloop.h>

#include <string.h>
#include <iostream>
#include <GL/glew.h>
#include <glfw3.h>
#include <ctime>

/**set the total fps and time*/
const double Gameloop::FPS = 60;
int Gameloop::timer = 0;

/**Constructor for the gameloop*/
Gameloop::Gameloop() {
	//make the gameloop able to run
	running=true;
	lastFrame = 0;
	//initiate the state manager
	manager = new StateManager();
	//initiate the game window
	window = new Window(800, 600, NULL);
	//initialise the current state
	currentState = manager->initialiseState();
}

/**delete the gathered recourses*/
Gameloop::~Gameloop() {
	//delete manager and window
	delete manager;
	delete window;
}

/**the core game loop*/
void Gameloop::gameLoop() {
	//time in ms, when last updated
	double lastUpdateTime = getTime();
	//average time in ms per frame
	const double TIME = 1000 / FPS;
	//maximum number of updates per frame
	const int MAXSKIP = 1;
	//counts the number of updates
	int loops=0;
	//counter for the actual frames and updates
	int countFrames=0;
	int renders=0;
	int lastSecondTime = (int) (lastUpdateTime / 1000);

	while (running && !window->closeWindow()) {

		//Update the Game and Handling Input
		loops=0;
		while ((getTime()>lastUpdateTime) && (loops < MAXSKIP)) {
			//update and handle input
			update();
			handleInput();

			//increase the updateTime
			lastUpdateTime += TIME;
			loops++;
			timer++;

			countFrames++;
		}

		// Render the game
		//calculate an interpolation to aid the rendering
		float interpolation = float(getTime() + TIME - lastUpdateTime)/ float( TIME);
		render(interpolation);
		renders++;

		//calculate the current second
		//print out the frames and updates
		int thisSecond = (int) (lastUpdateTime / 1000);
		if (thisSecond > lastSecondTime){
			std::cout << "NEW SECOND " << thisSecond << " " << countFrames  << " Renders: " << renders << std::endl;
	    	countFrames=0;
			renders=0;
        	lastSecondTime = thisSecond;
		}
	}
}


/**Will return time in milliseconds*/
long Gameloop::getTime(){
	return clock();
}


/**stop the game loop*/
void Gameloop::stopLoop(){
	running=false;
}

/**rendering the screen*/
void Gameloop::render(float interpolation){
	//clears the screen to black
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	//do the rendering
	currentState->renderGame(interpolation);

	//Swap front and back buffers
    window->swapBuffer();
}

/**update the game logic*/
void Gameloop::update(){
	//update game positions
	currentState->updateGame(timer);
	if (currentState->stateChanger()!=0){
		//change the state
		changeState(manager->callStates(currentState->stateChanger(), currentState->getKeyCode(), currentState));
	}
}

/**Poll for and process events*/
void Gameloop::handleInput(){
	//let the window collect input
    window->handleInput();
    //forward the input
	currentState->handleInput(window->getWindow());
}

/**change the state*/
void Gameloop::changeState(StateMachine* level){
	currentState = level;
}

